using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;

using PHSRAG.Insight21.BusinessObjects;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.ClinicalTrials
{
   /// <summary>
   /// The BudgetTasks class represents a collection of BudgetTask objects.  It is 
   /// responsible for loading and saving the Budget Tasks
   /// </summary>
   public class BudgetTasks : SaveableBusinessObject, IEnumerable
   {

      #region Constants
      private const string BudgetTasksKey = "BudgetTasks_0A7C68A2-2BFA-4e01-9207-141743F8225A";
      private const string TableName = "BudgetTasks";
      #endregion

      #region Instance Variables
      private ArrayList budgetTasks = new ArrayList( );
      private Budget budget;
      private SqlCommand updateBudgetTasksCommand;
      private SqlCommand deleteBudgetTasksCommand;
      #endregion

      #region Constructor
      /// <summary>
      /// Initialize the base class with the specified cache policy and create the data container.
      /// </summary>
      public BudgetTasks( ICachePolicy cachePolicy ) : base ( cachePolicy )
      {
         DataContainer = new DataSet( );
         budget = (Budget)CachePolicy.GetCachedObject( Budget.CacheKey );
      }
      #endregion
   
      #region Base Methods
      /// <summary>
      /// Cache this instance using the prevalent cache policy.
      /// </summary>
      public override void Cache( )
      {
         CachePolicy.Cache( BudgetTasksKey, this );
      }

      /// <summary>
      /// Remove this instance from the cache using the prevalent cache policy.
      /// </summary>
      public override void UnCache( )
      {
         CachePolicy.UnCache( BudgetTasksKey );
      }

      /// <summary>
      /// Load Task details pertaining to a specific budget.
      /// </summary>
      /// <param name="connectionString">Connection string to the database</param>
      /// <param name="args">Object array which must contain the budget ID.</param>
      public override void Load( string connectionString, params object[] args )
      {
         if ( args.Length != 1 )
            throw new Exception("BudgetTasks load requires a budget id.");
			
         DataAccess.LoadDataSet( DataContainer, TableName, connectionString, "GetClinicalTrialBudgetTasks", 
            Utility.DataAccess.BuildSqlParameterArray( "@budgetId", SqlDbType.Int, args[0] ) );

         if ( DataContainer.Tables.Count == 0 )
            throw new Exception("Failed to load Budget Task information.");

         foreach( DataRow budgetTaskRow in DataContainer.Tables[TableName].Rows )
         {
            budgetTasks.Add( new BudgetTask( CachePolicy, budgetTaskRow ) );
         }
      }

      /// <summary>
      /// Saves Task details associated with this budget.  
      /// </summary>
      /// <param name="connectionString">Connection string to the database</param>
      /// <param name="args">Optional parameters (ignored)</param>
      public override void Save( string connectionString, params object[] args )
      {
         SqlConnection connection = new SqlConnection( connectionString );
         SqlTransaction transaction = null;
         try
         {
            connection.Open( );
            transaction = connection.BeginTransaction( );
            BuildCommands( );
            updateBudgetTasksCommand.Connection = connection;
            updateBudgetTasksCommand.Transaction = transaction;
            deleteBudgetTasksCommand.Connection = connection;
            deleteBudgetTasksCommand.Transaction = transaction;

            SqlDataAdapter adapter = new SqlDataAdapter( );
            adapter.InsertCommand = updateBudgetTasksCommand;
            adapter.UpdateCommand = updateBudgetTasksCommand;
            adapter.DeleteCommand = deleteBudgetTasksCommand;
            adapter.Update( DataContainer, TableName );

            foreach ( BudgetTask budgetTask in budgetTasks )
            {
				if (budgetTask.Id != 0)
				{
					foreach ( BudgetMilestoneVisit budgetMilestoneVisit in budgetTask.BudgetMilestoneVisits )
					{
						budgetMilestoneVisit.RelateId = budgetTask.Id;
					}
					budgetTask.BudgetMilestoneVisits.Save( connectionString );
				}
            }
            transaction.Commit( );
         }
         catch( Exception e )
         {
            transaction.Rollback( );
            throw(new Exception(@"Error saving Budget Tasks to the database.", e));
         }
         finally
         {
            if ( connection.State != ConnectionState.Closed )
               connection.Close( );
            transaction.Dispose( );
         }
      }
      #endregion

      #region Private Methods
      private void BuildCommands( )
      {
         if ( updateBudgetTasksCommand == null )
         {
            updateBudgetTasksCommand = new SqlCommand( );
            updateBudgetTasksCommand.CommandText = "UpdateClinicalTrialBudgetTasks";
            updateBudgetTasksCommand.CommandType = CommandType.StoredProcedure;
			updateBudgetTasksCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			SqlParameter paramId = new SqlParameter( "@budgetTaskId", SqlDbType.Int );
            paramId.SourceColumn = "Id";
            paramId.Direction = ParameterDirection.InputOutput;
            updateBudgetTasksCommand.Parameters.Add( paramId );
            updateBudgetTasksCommand.Parameters.Add( "@budgetId", SqlDbType.Int ).SourceColumn = "ClinicalTrialBudgetId";
            updateBudgetTasksCommand.Parameters.Add( "@budgetStaffId", SqlDbType.Int ).SourceColumn = "ClinicalTrialBudgetStaffId";
            updateBudgetTasksCommand.Parameters.Add( "@budgetTaskCode", SqlDbType.VarChar ).SourceColumn = "BudgetTaskCode";
            updateBudgetTasksCommand.Parameters.Add( "@hours", SqlDbType.Decimal ).SourceColumn = "Hours";
            updateBudgetTasksCommand.Parameters.Add( "@otherTaskText", SqlDbType.VarChar ).SourceColumn = "OtherTaskText";
            updateBudgetTasksCommand.Parameters.Add( "@taskCost", SqlDbType.Decimal ).SourceColumn = "TaskCost";
            updateBudgetTasksCommand.Parameters.Add( "@applyOverhead", SqlDbType.Bit ).SourceColumn = "ApplyOverhead";
			updateBudgetTasksCommand.Parameters.Add( "@overRide", SqlDbType.Bit ).SourceColumn = "OverRideRate";
		 }

         if ( deleteBudgetTasksCommand == null )
         {
            deleteBudgetTasksCommand = new SqlCommand( );
            deleteBudgetTasksCommand.CommandText = "DeleteClinicalTrialBudgetTasks";
            deleteBudgetTasksCommand.CommandType = CommandType.StoredProcedure;
			deleteBudgetTasksCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			SqlParameter paramDeleteId = new SqlParameter( "@budgetTaskId", SqlDbType.Int );
            paramDeleteId.SourceColumn = "Id";
            paramDeleteId.Direction = ParameterDirection.Input;
            deleteBudgetTasksCommand.Parameters.Add( paramDeleteId );
         }
      }
      #endregion

      #region IEnumerable Methods
      /// <summary>
      /// Gets an IEnumerator interface.  Required for implementation of IEnumerable
      /// </summary>
      /// <returns>IEnumerator</returns>
      public IEnumerator GetEnumerator( )
      {
		   return budgetTasks.GetEnumerator( );
      }
      #endregion

      #region Public Collection helpers
      /// <summary>
      /// The Count property returns the number of items in the Budget Tasks collection
      /// </summary>
      public int Count
      {
         get
         {
            return budgetTasks.Count;
         }
      }

      /// <summary>
      /// Indexer to get a specific Budget Task from the collection
      /// </summary>
      public BudgetTask this[int index]
      {
         get
         {
            return (BudgetTask)budgetTasks[ index ];
         }
      }
      #endregion

      #region Public Methods
      /// <summary>
      /// Creates a new BudgetTask and adds the item to the collection.  Also sets default
      /// properties on the BudgetTask.
      /// </summary>
      /// <returns>BudgetTask</returns>
      public BudgetTask CreateNewBudgetTask( )
      {
         DataRow newRow = DataContainer.Tables[TableName].NewRow( );
         DataContainer.Tables[TableName].Rows.Add( newRow );
         BudgetTask newBudgetTask = new BudgetTask( CachePolicy, newRow );
         newBudgetTask.BudgetId = budget.Id;
         newBudgetTask.ApplyOverhead = true;
	     newBudgetTask.OverRideRate = false;
         // Setup the budgetmilestonevisits
         BudgetVisits budgetVisits = budget.BudgetVisits;
         foreach ( BudgetVisit budgetVisit in budgetVisits )
         {
            newBudgetTask.BudgetMilestoneVisits.CreateNewBudgetMilestoneVisit( budgetVisit.Id, "BudgetTask" );
         }
         budgetTasks.Add( newBudgetTask );
		 return newBudgetTask;
      }

      /// <summary>
      /// Removes a specific BudgetTask from the collection.  Must call save on BudgetTasks
      /// to save this change to the database.
      /// </summary>
      /// <param name="budgetTask">BudgetTask to remove from the collection.</param>
      public void RemoveBudgetTask( BudgetTask budgetTask )
      {
		  if(budgetTask.Id == 0) 
		  {
			  DataContainer.Tables[TableName].Rows.RemoveAt(  DataContainer.Tables[TableName].Rows.Count - 1 );
		  }
		  else
		  {
			  DataContainer.Tables[TableName].Select( string.Format( "Id = {0}", budgetTask.Id ) )[0].Delete( );
		  }
		  budgetTasks.Remove( budgetTask );
      }
      #endregion
   }
}